{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d006b2ea-9dfe-49c7-88a9-a5a0775185fd",
   "metadata": {},
   "source": [
    "# Additional End of week Exercise - week 2\n",
    "\n",
    "Now use everything you've learned from Week 2 to build a full prototype for the technical question/answerer you built in Week 1 Exercise.\n",
    "\n",
    "This should include a Gradio UI, streaming, use of the system prompt to add expertise, and the ability to switch between models. Bonus points if you can demonstrate use of a tool!\n",
    "\n",
    "If you feel bold, see if you can add audio input so you can talk to it, and have it respond with audio. ChatGPT or Claude can help you, or email me if you have questions.\n",
    "\n",
    "I will publish a full solution here soon - unless someone beats me to it...\n",
    "\n",
    "There are so many commercial applications for this, from a language tutor, to a company onboarding solution, to a companion AI to a course (like this one!) I can't wait to see your results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a07e7793-b8f5-44f4-aded-5562f633271a",
   "metadata": {},
   "outputs": [],
   "source": [
    "ONLINE TRIP PLANNING ASSISTANT"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7ea68f58-8b6f-418d-b04c-98e38147a2c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# imports\n",
    "\n",
    "import os\n",
    "import json\n",
    "from dotenv import load_dotenv\n",
    "from openai import OpenAI\n",
    "import gradio as gr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "80fd1847-3f5e-4e9b-8b54-b4ca5923aaa8",
   "metadata": {},
   "outputs": [],
   "source": [
    "force_dark_mode = \"\"\"\n",
    "function refresh() {\n",
    "    const url = new URL(window.location);\n",
    "    if (url.searchParams.get('__theme') !== 'dark') {\n",
    "        url.searchParams.set('__theme', 'dark');\n",
    "        window.location.href = url.href;\n",
    "    }\n",
    "}\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "212f6842-6058-4246-8d84-c4bcc1f1a651",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialization\n",
    "\n",
    "load_dotenv(override=True)\n",
    "\n",
    "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
    "if openai_api_key:\n",
    "    print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"OpenAI API Key not set\")\n",
    "    \n",
    "MODEL = \"gpt-4o-mini\"\n",
    "openai = OpenAI()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e4980d17-a8a1-4347-9a0c-56a57c93d063",
   "metadata": {},
   "outputs": [],
   "source": [
    "system_message=\"You are the AI trip planner assistant your job is to analyse the user message and give clear and crisp response based on their queries.\"\n",
    "system_message+=\"Only if they are asking you specifically for iternary for their trip destination for the required number of days provided by them in the user message. for example\"\n",
    "system_message+=\"user: I want a plan for Ooty trip for 3 days.\" \n",
    "system_message+=\"then you need to provide an clear simple iternary for OOty for 3 days. Like Day1 this place, this place Day 2 this place this place in a good format.\"\n",
    "system_message+=\"Always be accurate if you don't know the answer say so.\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a215d7c8-5c3f-4f10-b492-a70d48814010",
   "metadata": {},
   "outputs": [],
   "source": [
    "# This function looks rather simpler than the one from my video, because we're taking advantage of the latest Gradio updates\n",
    "\n",
    "def chat(message, history):\n",
    "    messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
    "    response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
    "    return response.choices[0].message.content\n",
    "\n",
    "gr.ChatInterface(fn=chat, type=\"messages\",js=force_dark_mode).launch()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fe328993-5b14-4909-a2c5-3e0cd1bc8a5e",
   "metadata": {},
   "outputs": [],
   "source": [
    "#let add mulitmodal feature image \n",
    "import base64\n",
    "from io import BytesIO\n",
    "from PIL import Image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8fb145ee-2537-48a4-80b0-7921d79669be",
   "metadata": {},
   "outputs": [],
   "source": [
    "def artist(city):\n",
    "    image_response = openai.images.generate(\n",
    "            model=\"dall-e-3\",\n",
    "            prompt=f\"An image representing a vacation in {city}, showing tourist spots and everything unique about {city}, in a vibrant pop-art style\",\n",
    "            size=\"1024x1024\",\n",
    "            n=1,\n",
    "            response_format=\"b64_json\",\n",
    "        )\n",
    "    image_base64 = image_response.data[0].b64_json\n",
    "    image_data = base64.b64decode(image_base64)\n",
    "    return Image.open(BytesIO(image_data))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c475aae4-79a4-4a49-b846-b01b6a67000d",
   "metadata": {},
   "outputs": [],
   "source": [
    "#now lets implement tools for checking the ticket price and for demo flight booking assitance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0c047872-df5c-4ea1-bc43-0c5da596aac7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Add this import at the top\n",
    "from reportlab.lib.pagesizes import letter\n",
    "from reportlab.pdfgen import canvas\n",
    "from reportlab.lib.units import inch\n",
    "from datetime import datetime\n",
    "import io\n",
    "import base64\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ceeb60f7-ac79-46d8-bbf3-5fab163d9ccf",
   "metadata": {},
   "outputs": [],
   "source": [
    "#for checking ticket price\n",
    "\n",
    "ticket_prices = {\"london\": \"$799\", \"paris\": \"$899\", \"tokyo\": \"$1400\", \"berlin\": \"$499\"}\n",
    "\n",
    "def get_ticket_price(destination_city):\n",
    "    print(f\"Tool get_ticket_price called for {destination_city}\")\n",
    "    city = destination_city.lower()\n",
    "    return ticket_prices.get(city, \"Unknown\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9b92db79-87ba-48ec-840b-a54e3d5cb5cc",
   "metadata": {},
   "outputs": [],
   "source": [
    "#for flight booking\n",
    "# Add the booking function\n",
    "def book_flight(destination_city, travel_date, passenger_name=\"Traveler\"):\n",
    "    print(f\"Tool book_flight called for {destination_city} on {travel_date}\")\n",
    "    \n",
    "    # Generate a simple PDF ticket\n",
    "    buffer = io.BytesIO()\n",
    "    c = canvas.Canvas(buffer, pagesize=letter)\n",
    "    width, height = letter\n",
    "    \n",
    "    # Draw ticket\n",
    "    c.setFont(\"Helvetica-Bold\", 24)\n",
    "    c.drawString(2*inch, height - 2*inch, \"FLIGHT TICKET\")\n",
    "    \n",
    "    c.setFont(\"Helvetica\", 12)\n",
    "    c.drawString(1*inch, height - 3*inch, f\"Passenger: {passenger_name}\")\n",
    "    c.drawString(1*inch, height - 3.5*inch, f\"Destination: {destination_city.upper()}\")\n",
    "    c.drawString(1*inch, height - 4*inch, f\"Travel Date: {travel_date}\")\n",
    "    c.drawString(1*inch, height - 4.5*inch, f\"Booking Reference: BK{datetime.now().strftime('%Y%m%d%H%M%S')}\")\n",
    "    c.drawString(1*inch, height - 5*inch, f\"Price: {ticket_prices.get(destination_city.lower(), 'N/A')}\")\n",
    "    c.drawString(1*inch, height - 6*inch, \"Status: CONFIRMED ✓\")\n",
    "    \n",
    "    c.save()\n",
    "    \n",
    "    pdf_bytes = buffer.getvalue()\n",
    "    buffer.close()\n",
    "    \n",
    "    return base64.b64encode(pdf_bytes).decode(), destination_city, travel_date\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "51e9a429-dafa-4fdf-9e30-bef07b78a1b3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# There's a particular dictionary structure that's required to describe our function:\n",
    "\n",
    "price_function = {\n",
    "    \"name\": \"get_ticket_price\",\n",
    "    \"description\": \"Get the price of a return ticket to the destination city. Call this whenever you need to know the ticket price, for example when a customer asks 'How much is a ticket to this city'\",\n",
    "    \"parameters\": {\n",
    "        \"type\": \"object\",\n",
    "        \"properties\": {\n",
    "            \"destination_city\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"The city that the customer wants to travel to\",\n",
    "            },\n",
    "        },\n",
    "        \"required\": [\"destination_city\"],\n",
    "        \"additionalProperties\": False\n",
    "    }\n",
    "}\n",
    "\n",
    "booking_function = {\n",
    "    \"name\": \"book_flight\",\n",
    "    \"description\": \"Book a flight ticket to the destination city for a specific date. Call this when a customer wants to book a flight and provides a travel date.\",\n",
    "    \"parameters\": {\n",
    "        \"type\": \"object\",\n",
    "        \"properties\": {\n",
    "            \"destination_city\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"The destination city for the flight\",\n",
    "            },\n",
    "            \"travel_date\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"The date of travel in format YYYY-MM-DD or any date format provided by user\",\n",
    "            },\n",
    "            \"passenger_name\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"The name of the passenger (optional)\",\n",
    "            }\n",
    "        },\n",
    "        \"required\": [\"destination_city\", \"travel_date\"],\n",
    "        \"additionalProperties\": False\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0912f99b-1650-4c40-8249-5fe808c85c75",
   "metadata": {},
   "outputs": [],
   "source": [
    "tools = [\n",
    "    {\"type\": \"function\", \"function\": price_function},\n",
    "    {\"type\": \"function\", \"function\": booking_function}\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fdc5b499-c6f2-48fd-a6ee-304f7dbe8b0e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Update handle_tool_call to handle both tools\n",
    "def handle_tool_call(message):\n",
    "    tool_call = message.tool_calls[0]\n",
    "    arguments = json.loads(tool_call.function.arguments)\n",
    "    \n",
    "    if tool_call.function.name == \"get_ticket_price\":\n",
    "        city = arguments.get('destination_city')\n",
    "        price = get_ticket_price(city)\n",
    "        response = {\n",
    "            \"role\": \"tool\",\n",
    "            \"content\": json.dumps({\"destination_city\": city, \"price\": price}),\n",
    "            \"tool_call_id\": tool_call.id\n",
    "        }\n",
    "        return response, city\n",
    "    \n",
    "    elif tool_call.function.name == \"book_flight\":\n",
    "        city = arguments.get('destination_city')\n",
    "        date = arguments.get('travel_date')\n",
    "        passenger = arguments.get('passenger_name', 'Traveler')\n",
    "        pdf_base64, city, date = book_flight(city, date, passenger)\n",
    "        response = {\n",
    "            \"role\": \"tool\",\n",
    "            \"content\": json.dumps({\n",
    "                \"destination_city\": city,\n",
    "                \"travel_date\": date,\n",
    "                \"status\": \"confirmed\",\n",
    "                \"ticket_pdf\": pdf_base64\n",
    "            }),\n",
    "            \"tool_call_id\": tool_call.id\n",
    "        }\n",
    "        return response, city"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b319f933-da42-4b78-8a07-fedab965abae",
   "metadata": {},
   "outputs": [],
   "source": [
    "def chat(message, history):\n",
    "    messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
    "    response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
    "    \n",
    "    pdf_file = None\n",
    "    image = None\n",
    "    \n",
    "    if response.choices[0].finish_reason == \"tool_calls\":\n",
    "        message_obj = response.choices[0].message\n",
    "        tool_response, city = handle_tool_call(message_obj)\n",
    "        \n",
    "        # Check which tool was called\n",
    "        if message_obj.tool_calls[0].function.name == \"get_ticket_price\":\n",
    "            image = artist(city)\n",
    "        \n",
    "        elif message_obj.tool_calls[0].function.name == \"book_flight\":\n",
    "            tool_content = json.loads(tool_response[\"content\"])\n",
    "            pdf_base64 = tool_content.get(\"ticket_pdf\")\n",
    "            \n",
    "            if pdf_base64:\n",
    "                # Decode and save PDF\n",
    "                pdf_bytes = base64.b64decode(pdf_base64)\n",
    "                pdf_file = f\"ticket_{city}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf\"\n",
    "                with open(pdf_file, \"wb\") as f:\n",
    "                    f.write(pdf_bytes)\n",
    "        \n",
    "        messages.append(message_obj)\n",
    "        messages.append(tool_response)\n",
    "        response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
    "    \n",
    "    return response.choices[0].message.content, pdf_file, image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49f91127-e282-409d-84b8-8d04eb902c74",
   "metadata": {},
   "outputs": [],
   "source": [
    "with gr.Blocks() as demo:\n",
    "    gr.Markdown(\"# 🌍 AI Trip Planner Assistant\")\n",
    "    \n",
    "    with gr.Row():\n",
    "        chatbot = gr.Chatbot(type=\"messages\", height=400)\n",
    "        image_output = gr.Image(height=400, interactive=False, show_label=False)\n",
    "    \n",
    "    with gr.Row():\n",
    "        msg = gr.Textbox(label=\"Your message\", placeholder=\"Ask about ticket prices or book a flight...\", scale=4)\n",
    "        send_btn = gr.Button(\"Send\", scale=1)\n",
    "    \n",
    "    file_output = gr.File(label=\"📄 Download Your Ticket\", visible=True)\n",
    "    \n",
    "    def respond(message, history):\n",
    "        bot_message, pdf_path, image = chat(message, history)\n",
    "        history.append({\"role\": \"user\", \"content\": message})\n",
    "        history.append({\"role\": \"assistant\", \"content\": bot_message})\n",
    "        return history, \"\", pdf_path, image\n",
    "    \n",
    "    msg.submit(respond, [msg, chatbot], [chatbot, msg, file_output, image_output])\n",
    "    send_btn.click(respond, [msg, chatbot], [chatbot, msg, file_output, image_output])\n",
    "\n",
    "demo.launch()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "23b746f6-94d7-44d7-9dec-b4f4dcdd6b61",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
